package objects.playable;

import objects.base.GravityObj;

import org.newdawn.slick.GameContainer;
import org.newdawn.slick.state.StateBasedGame;
import util.level.Room;

/**
 * This class implements a skeleton of methods
 * for playable characters to be implemented
 * depending on different control behavior.
 * 
 * @author John
 */

public class Player extends GravityObj
{
	// A list of keys for which input should be kept track of, can be overridden by child classes
	protected int keyList[] = {};
	protected boolean keyStates[];
	
	// Player behaviour constants
	protected static final float KNOCKBACK_Y = -7.3f;
	protected static final float KNOCKBACK_X = 7.6f;
	
	/**
	 * Initializes a generic player of given size at the given position.
	 * 
	 * @param initX - The initial X position.
	 * @param initY - The initial Y position.
	 * @param initWidth - The initial width of the object.
	 * @param initHeight - The initial height of the object.
	 */
	public Player(float initX, float initY, float initWidth, float initHeight)
	{
		super(initX, initY, initWidth, initHeight);
		// Initialize the keys to keep track of
		initKeys();
		// Include an additional motion vector for getting bumped
		this.setMotionVectors(2);
	}
	
	/**
	 * Initializes an array of booleans for each key whose input you want to track.
	 */
	protected void initKeys()
	{
		keyStates = new boolean[keyList.length];
	}
	
	/**
	 * Performs player input after movement.
	 * 
	 * @param gc {@inheritDoc}
	 * @param sbg {@inheritDoc}
	 * @param room {@inheritDoc}
	 */
	public void step(GameContainer gc, StateBasedGame sbg, Room room)
	{
		// Do movement
		super.step(gc,sbg,room);
		// Perform player input
		doControl(gc);
	}
	
	/**
	 * This method reads in player input and turns it into Joogle actions.
	 * 
	 * @param gc - Used to obtain input.
	 */
	protected void doControl(GameContainer gc)
	{
		// Read in input from all relevant keys
		for (int i = 0; i < keyList.length; i++)
		{
			keyStates[i] = gc.getInput().isKeyDown(keyList[i]);
		}

		// Perform horizontal motion functions
		limitXSpeed();
		accelerate();
		
		// Perform vertical motion functions
		limitYSpeed();
		jumpControl();
		adjustGravity();
	}
	
	/**
	 * Knocks back the player in the given direction.
	 * 
	 * @param direction - The direction to knock the player back in.
	 */
	public void doKnockback(boolean direction)
	{
		// Apply knockback force
		xMotion[1].speed = direction?-KNOCKBACK_X:KNOCKBACK_X;
		yMotion[1].speed = KNOCKBACK_Y;
		// Stop other motions
		xMotion[0].speed = 0;
		yMotion[0].speed = 0;
	}
	
	/**
	 * Applies limits on X speed.
	 */
	protected void limitXSpeed()
	{
		// Decrease knockback speed
		xMotion[1].speed -= xMotion[1].speed/8;
		// Limit knockback speed
		if (Math.abs(xMotion[1].speed) <= 0.125f) xMotion[1].speed = 0;
	}
	
	/**
	 * Applies limits on Y speed.
	 */
	protected void limitYSpeed() {}
	
	/**
	 * Performs acceleration based on key presses.
	 */
	protected void accelerate() {}
	
	/**
	 * Controls behaviour for jumping.
	 */
	protected void jumpControl() {}
	
	/**
	 * Changes gravity values for variable jumping.
	 */
	protected void adjustGravity() {}
	
	
}
